#ifndef _CAD_SLICER_SLICER_H_
#define _CAD_SLICER_SLICER_H_

#include <cad-slicer/fwd.h>

#include <vector>
#include <string>
#include <functional>

#include <cad-slicer/slicer-parameters.h>
#include <cad-slicer/slice.h>
#include <cad-slicer/object-properties.h>


namespace cadslicer
{

/**
 * @brief This class take an object and try to slice it in its
 *        bounding box.
 */
class slicer
{
public:

  typedef slicer_parameters parameters;

  slicer(void);
  explicit slicer(parameters const& param);
  explicit slicer(std::string const& param_file);

  ~slicer(void);

  void operator ()(Assimp::Importer& object);
  void operator ()(std::string const& input_file);

  bool set_parameters(parameters const& param);
  bool set_parameters(std::string const& param_file);

  inline parameters const&
  get_parameters(void) const
  { return _slicer_parameters; }

  std::vector<slice> const&
  get_slices(void) const
  { return _slices; }

  void check_parameters(void) const;

  object_properties const&
  get_object_properties(void) const
  { return _obj_prop; }

  /// @brief Use this if you want to treat each slice one computed
  ///        and not waiting that all the slices are computed.
  ///
  /// The function passed as argument will be called just after a
  /// slice has been computed.
  void set_slice_post_treatment(std::function<void(slice const&)> const& f)
  { _post_slice = f; }

private:

  bool find_object_dimensions(void const* object);
  void print_object_properties(void const* object);

  void slice_object(void);
  void repair_faces(void const* object);
  void insert_in_slice(
      slice& sl, vertex_id a, vertex_id b, vertex_id c);

  std::vector<slice> _slices;

  parameters _slicer_parameters;

  object_properties _obj_prop;

  std::function<void(slice const&)> _post_slice;

  typedef std::array<vertex_id, 3> triangle;
  std::forward_list<triangle> _filled_holls;
};

} // cadslicer

#endif // _CAD_SLICER_SLICER_H_
